package com.nami.gate.network.handler;

import cn.hutool.json.JSONUtil;
import com.nami.gate.config.RpcConfig;
import com.nami.gate.constants.ChannelConstants;
import com.nami.gate.external.basic.constants.UpTopicConst;
import com.nami.gate.external.basic.request.upmsg.HeartTimeoutRequest;
import com.nami.gate.middleware.mq.MqSender;
import com.nami.gate.process.upmsg.PackageProcessFactory;
import com.nami.im.network.model.packet.v2.Packet;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;


/**
 * 描述：
 *
 * @Author: lbc
 * @Date: 2023-07-14 15:38
 * @email: 594599620@qq.com
 * @Description: keep coding
 */
@Slf4j
public class NettyServerHandler extends SimpleChannelInboundHandler<Packet> {

    private PackageProcessFactory factory;
    private MqSender mqSender;
    private RpcConfig rpcConfig;

    public NettyServerHandler(MqSender mqSender,
                              RpcConfig rpcConfig,
                              PackageProcessFactory factory) {
        this.mqSender = mqSender;
        this.rpcConfig = rpcConfig;
        this.factory = factory;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端握手成功，[{}]通道激活. 准备认证！", ctx.channel().remoteAddress());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        try {
            Channel channel = ctx.channel();
            String userId = (String) channel.attr(AttributeKey.valueOf(ChannelConstants.USER_ID)).get();
            if (StringUtils.isNotBlank(userId)) {
                mqSender.send(UpTopicConst.CONNECT_TIMEOUT_TOPIC, JSONUtil.toJsonStr(newChannelCloseRequest(channel)));
            }
        } catch (Exception var3) {
            var3.printStackTrace();
            log.error("[inactive] 客户端异常处理出错了。err={}", var3.getMessage());
        }
        super.channelInactive(ctx);
    }

    @NotNull
    private static HeartTimeoutRequest newChannelCloseRequest(Channel channel) {
        HeartTimeoutRequest request = new HeartTimeoutRequest();
        request.setUserId((String) channel.attr(AttributeKey.valueOf(ChannelConstants.USER_ID)).get());
        request.setAppKey((String) channel.attr(AttributeKey.valueOf(ChannelConstants.APP_KEY)).get());
        request.setInstanceId((String) channel.attr(AttributeKey.valueOf(ChannelConstants.INSTANCE_ID)).get());
        request.setCurrTime(System.currentTimeMillis());
        log.info("[inactive] request={}", JSONUtil.toJsonStr(request));
        return request;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        log.error("[exception] 通道异常，msg={}", cause.getMessage());
        // 是否执行调用继续父类异常处理办法 TODO
//        super.exceptionCaught(ctx, cause);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext context, Packet packet) throws Exception {
        // question:
        //          是否需要启动一个线程池 加速处理上行消息
        // 2c4g 节点。感觉没必要再使用线程池去处理
        //   1. process方法轻量 向逻辑层发送mq消息就结束了 几ms
        //   2. 2核，多线程下还有线程切换开销
        //   3. netty 的worker已经是多线程
        factory.getMessageProcess(packet.getCmd())
            .process(context.channel(), packet);
    }

}
